#pragma once
#include "Frame.pb.h"
#include "Request.pb.h"
#include "Response.pb.h"
#include <boost/asio.hpp>
#include <functional>
#include <map>
#include <string>
#include <variant>
#include <vector>

namespace MRMDS::Client
{
using VariantValue = std::variant<int, float, double, std::string>;
struct Message
{
    int sender;
    std::map<std::string, VariantValue> args;
};

class Client
{
  public:
    void Connect(std::string ip, int port);
    void Disconnect();
    bool LogIn(std::string passward, std::string name);
    bool LogOut();
    bool GetInstanceList(int filter, std::map<int, std::string> &instances);
    bool GetValue(std::vector<int> ids, std::vector<int> keys, std::map<int, std::map<int, VariantValue>> &values);
    bool SetValue(std::map<int, VariantValue> &values);

  private:
    int id;
    boost::asio::io_context ioctx;
    std::unique_ptr<boost::asio::ip::tcp::socket> socket;
    std::array<char, 1024> buffer;
    template <class T> void SendRequest(T req);
    void ReceiveResponse(MRMDS::Message::Response &rep);
    template <class T> void InvokeRequest(T req, MRMDS::Message::Response &rep)
    {
        SendRequest(req);
        ReceiveResponse(rep);
    }
};
} // namespace MRMDS::Client
